
#include "TileManager.h"
#include "Tile.h"
#include "..\\..\\TinyXML\\tinyxml2.h"
#include "..\\..\\SGD Wrappers\\SGD_GraphicsManager.h"
#include "..\\Game Objects\\Camera.h"
#include "..\\Game.h"

#include <sstream>

TileManager::TileManager()
{
	iNumLayers = 0;
}


TileManager::~TileManager()
{
	Clear();
}

void TileManager::Clear()
{
	mTiles.clear();
	if (hTileset != SGD::INVALID_HANDLE)
		GRAPHICS->UnloadTexture(hTileset);
	hTileset = SGD::INVALID_HANDLE;
}

void TileManager::Render()
{
	Camera* camera = Camera::GetInstance();
	SGD::Point offset = camera->GetPosition();
	int startX = (int)(camera->GetPosition().x / GetTileSize().width) - 1;
	int startY = (int)(camera->GetPosition().y / GetTileSize().height) - 1;
	int eX = (int)((camera->GetPosition().x + SCREEN_WIDTH) / GetTileSize().width) + 1;
	int eY = (int)((camera->GetPosition().y + SCREEN_HEIGHT) / GetTileSize().height) + 1;
	if (startX < 0)
		startX = 0;
	if (eX >(int)GetLevelSize().width)
		eX = (int)GetLevelSize().width;
	if (startY < 0)
		startY = 0;
	if (eY >(int)GetLevelSize().height)
		eY = (int)GetLevelSize().height;

	int drawnTiles = 0;
	for (int l = 0; l < iNumLayers; ++l)
	{
		int x = startX;
		for (; x < eX; ++x)
		{
			int y = startY;
			for (; y < eY; ++y)
			{
				Tile t = mTiles[TileKey(l, x, y)];
				if (t.GetX() == -1)
					continue;
				++drawnTiles;
				SGD::Point pos = SGD::Point(x * GetTileSize().width, y * GetTileSize().height);
				pos.x -= offset.x;
				pos.y -= offset.y;

				SGD::Rectangle srcRect;
				srcRect.left = t.GetX() * GetTileSize().width;
				srcRect.top = t.GetY() * GetTileSize().height;
				srcRect.right = srcRect.left + GetTileSize().width;
				srcRect.bottom = srcRect.top + GetTileSize().height;

				GRAPHICS->DrawTextureSection(hTileset, pos, srcRect);
			}
		}
	}
	drawnTiles = drawnTiles;
}

void TileManager::Load(std::string filePath)
{
	tinyxml2::XMLDocument doc;
	

	if (mTiles.size() > 0)
		mTiles.clear();
	if (mHeightMap.size() > 0)
		mHeightMap.clear();
	if (vLiquids0.size() > 0)
		vLiquids0.clear();
	if (vLiquids1.size() > 0)
		vLiquids1.clear();

	if (tinyxml2::XML_NO_ERROR == doc.LoadFile(filePath.c_str()))
	{
		tinyxml2::XMLElement* pRoot = doc.RootElement();

		if (pRoot != nullptr)
		{
			int sX, sY;
			sX = pRoot->IntAttribute("LevelWidth");
			sY = pRoot->IntAttribute("LevelHeight");
			LevelSize.width = (float)sX;
			LevelSize.height = (float)sY;

			sX = pRoot->IntAttribute("TileSetWidth");
			sY = pRoot->IntAttribute("TileSetHeight");
			TilesetSize.width = (float)sX;
			TilesetSize.height = (float)sY;

			sX = pRoot->IntAttribute("TileWidth");
			sY = pRoot->IntAttribute("TileHeight");
			TileSize.width = (float)sX;
			TileSize.height = (float)sY;

			GAME->SetBottomOfLevel((int)LevelSize.height * (int)TileSize.height);

			std::string sTilesetPath;
			sTilesetPath = pRoot->Attribute("TileSetFile");
			sTilesetPath = "Resource/" + sTilesetPath;

			hTileset = GRAPHICS->LoadTexture(sTilesetPath.c_str());	// Load image handle

			tinyxml2::XMLElement* pLayer;
			pLayer = pRoot->FirstChildElement("Layer");

			int iLayerCount = 0;
			while (pLayer)
			{
				tinyxml2::XMLElement* pLevel;
				pLevel = pLayer->FirstChildElement("Level");

				tinyxml2::XMLElement* pTile;
				pTile = pLevel->FirstChildElement("Tile");

				while (pTile)
				{
					int locX = pTile->IntAttribute("TileMapCoordX");
					int locY = pTile->IntAttribute("TileMapCoordY");

					Tile tempTile;

					int tileSetX = pTile->IntAttribute("TileSetCoordX");
					int tileSetY = pTile->IntAttribute("TileSetCoordY");
					
					tempTile.SetX(tileSetX);
					tempTile.SetY(tileSetY);

					if (tileSetX == 0)
					{
						if (tileSetY == 1)
						{
							vLiquids0.push_back(SGD::Point(locX * GetTileSize().width, locY * GetTileSize().height));
						}
						else if (tileSetY == 2)
						{
							vLiquids1.push_back(SGD::Point(locX * GetTileSize().width, locY * GetTileSize().height));
						}
					}

					mTiles[TileKey(iLayerCount, locX, locY)] = tempTile;

					pTile = pTile->NextSiblingElement("Tile");
				}
				pLayer = pLayer->NextSiblingElement("Layer");			// Go to next layer
				++iLayerCount;											// Increment layer count
			}

			iNumLayers = iLayerCount;
			pLayer = pRoot->FirstChildElement("Heightmaps");
			pLayer = pLayer->FirstChildElement("Heightmap");

			int tileNum = 0;
			while (pLayer)
			{
				for (int h = 0; h < GetTileSize().width; h++)
				{
					std::string heightAtt = "Height";
					std::ostringstream oss;
					oss << h;
					heightAtt += oss.str();
					int height = pLayer->IntAttribute(heightAtt.c_str());
					mHeightMap[HeightKey(tileNum, h)] = height;
					oss.clear();
				}
				++tileNum;
				pLayer = pLayer->NextSiblingElement("Heightmap");
			}
		}
	}
}

typedef std::vector< GameObject* >		EntityVector;

void TileManager::CheckCollisions(unsigned int bucket)
{
	unsigned int entSize = GAME->GetEntityManager().GetEntities(bucket).size();
	if (bucket >= entSize || entSize == 0)
	{
		return;
	}

	TileManager* tm = GAME->GetTileManager();
	Camera* camera = Camera::GetInstance();
	SGD::Point offset = camera->GetPosition();
	int startX = (int)(camera->GetPosition().x / GetTileSize().width) - 1;
	int startY = (int)(camera->GetPosition().y / GetTileSize().height) - 1;
	int eX = (int)((camera->GetPosition().x + SCREEN_WIDTH) / GetTileSize().width) + 1;
	int eY = (int)((camera->GetPosition().y + SCREEN_HEIGHT) / GetTileSize().height) + 1;
	if (startX < 0)
		startX = 0;
	if (eX >(int)GetLevelSize().width)
		eX = (int)GetLevelSize().width;
	if (startY < 0)
		startY = 0;
	if (eY >(int)GetLevelSize().height)
		eY = (int)GetLevelSize().height;

	EntityVector& vObjects = GAME->GetEntityManager().GetEntities(bucket);

	for (unsigned int i = 0; i < entSize; i++)
	{
		if (vObjects[i]->IsOnCamera())
		{
			int x = startX;
			for (; x < eX; ++x)
			{
				int y = startY;
				for (; y < eY; ++y)
				{
					Tile t = mTiles[TileKey(0, x, y)];
					if (t.GetX() == -1)
						continue;
					
					// tm == TileManager located in Game

				}
			}

			//vecLayers[i].CheckCollisions(GetLevelSize().width, GetLevelSize().height, GetTileSize().width, GetTileSize().height, vObjects[i]);
		}
	}
}

int TileManager::GetTileHeightMap(int x, int y, int height)
{
	Tile t = mTiles[TileKey(0, x, y)];
	if (t.GetX() == -1 || t.GetX() == 0 && t.GetY() == 0)
		return -1;
	int index = t.GetY() + t.GetX() * (int)GetTilesetSize().height;
	int h = mHeightMap[HeightKey(index, height)];
	return h;
}

int TileManager::GetTileIndex(int x, int y)
{
	Tile t = mTiles[TileKey(0, x, y)];
	return t.GetY() + t.GetX() * (int)GetTilesetSize().height;
}

SGD::Size TileManager::GetTileSize()
{
	return TileSize;
}

SGD::Size TileManager::GetTilesetSize()
{
	return TilesetSize;
}

SGD::Size TileManager::GetLevelSize()
{
	return LevelSize;
}
